package org.com.lcuiot.handler;
import com.google.gson.Gson;
import org.com.lcuiot.common.LcuConst;
import org.com.lcuiot.database.dto.Result;
import org.com.lcuiot.database.entity.Account;
import org.com.lcuiot.security.AsymmetricEncrypt;
import org.com.lcuiot.security.AuthRequest;
import org.com.lcuiot.security.AuthenticationPacket;
import org.com.lcuiot.security.JwtTokenProvider;
import org.com.lcuiot.service.AccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.util.Base64;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

/**
 * 登录注册处理器
 *
 * @author gaoge
 * @since 2022/11/21 16:36
 */
@RestController
public class AuthHandler extends AbstractHandler {
    private static final Logger logger = LoggerFactory.getLogger(AuthHandler.class);
    private final ReactiveAuthenticationManager authenticationManager;
    private final JwtTokenProvider jwtTokenProvider;
    private final AccountService accountService;
    private final StringRedisTemplate stringRedisTemplate;
    private final Gson gson = new Gson();

    @Autowired
    public AuthHandler(ReactiveAuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider, AccountService accountService, StringRedisTemplate stringRedisTemplate) {
        this.authenticationManager = authenticationManager;
        this.jwtTokenProvider = jwtTokenProvider;
        this.accountService = accountService;
        this.stringRedisTemplate = stringRedisTemplate;
    }


    @Bean
    public RouterFunction<ServerResponse> authRouter() {
        return route()
                .POST("/auth/login", this::login)
                .POST("/auth/register", this::register)
                .GET("/auth/login_key", this::loginKey)
                .build();
    }

    /**
     * 登陆
     *
     * @param request 请求信息
     * @return Mono<ServerResponse>
     * @author gaoge
     */
    public Mono<ServerResponse> login(ServerRequest request) {
        return request.bodyToMono(AuthenticationPacket.class).flatMap(s -> {
            String privateKey = stringRedisTemplate.opsForValue().get(LcuConst.PASSWORD_ENCODER_PublicKey + s.getKey());
            if (!StringUtils.hasLength(privateKey)) {
                return resolveResult(Result.build().setCode(500).setMsg("私钥过期登录信息失效请重新登录"));
            }
            AuthRequest authRequest = new AuthRequest("占-位-符","占-位-符");
            try {
                byte[] cipherBytes = Base64.getDecoder().decode(s.getCryptogram());
                byte[] plainBytes = AsymmetricEncrypt.decrypt(cipherBytes, privateKey);
                logger.info("登陆信息：{}" ,new String(plainBytes));
                authRequest = gson.fromJson(new String(plainBytes), AuthRequest.class);
            } catch (Exception e) {
                return resolveResult(Result.build().setCode(500).setMsg("登录信息失效请重新登录"));
            }
            Mono<Authentication> authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword()));
            return authentication.flatMap(auth -> ok().body(fromValue(Result.build().setData(jwtTokenProvider.createToken(auth)))));

        });
    }

    /**
     * 注册
     *
     * @param request 请求信息
     * @return Mono<ServerResponse>
     * @author gaoge
     */
    public Mono<ServerResponse> register(ServerRequest request) {
        return request.bodyToMono(Account.class).flatMap(s -> {
            Result<Object> result = accountService.register(s);
            return resolveResult(result);
        });
    }

    /**
     * 登陆前获取公钥
     *
     * @param request 请求信息
     * @return Mono<ServerResponse>
     * @author gaoge
     */
    public Mono<ServerResponse> loginKey(ServerRequest request) {
        Result<Object> result = accountService.cryptoKey();
        return resolveResult(result);
    }
}